package cn.jesin.css.filter;


import cn.hutool.core.util.StrUtil;
import cn.jesin.css.vo.OtherAuthInfo;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author 谷汉斌
 * @description 自定义认证（登录）过滤器
 * @createTime 2024/7/31 下午4:43
 */
@Slf4j
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {


    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
        log.info("开始执行CustomAuthenticationFilter*************");
        //获取请求头，据此判断请求参数类型
        String contentType = request.getContentType();
        if (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType)) {
            //说明请求参数是 JSON
            if (!"POST".equals(request.getMethod())) {
                throw new AuthenticationServiceException("不支持的登录请求方式！" + request.getMethod());
            }
            //提取用户唯一标识和登录凭据，授权平台，登录方式
            String userOnlyId;
            String userCredential;
            String othType;
            String loginType;
            //构建登录令牌
            UsernamePasswordAuthenticationToken authRequest;
            try (InputStream is = request.getInputStream()) {
                //解析请求体中的 JSON 参数
                OtherAuthInfo otherAuthInfo = JSON.parseObject(is.readAllBytes(), OtherAuthInfo.class);
                userOnlyId = otherAuthInfo.oAuthOnlyId();
                //用户唯一标识
                if (StrUtil.isBlank(userOnlyId)) {
                    throw new AuthenticationServiceException("用户唯一标识不能为空！");
                }
                //登录凭据
                userCredential = otherAuthInfo.getCredintials();
                if (StrUtil.isBlank(userCredential)) {
                    throw new AuthenticationServiceException("登录凭据不能为空！");
                }
                //授权平台类型类型
                othType = otherAuthInfo.getOthType();
                if (StrUtil.isBlank(othType)) {
                    throw new AuthenticationServiceException("授权平台类型不能为空！");
                }
                //登录方式
                loginType = otherAuthInfo.getLoginType();
                if (StrUtil.isBlank(loginType)) {
                    throw new AuthenticationServiceException("登录方式不能为空！");
                }
                log.info("尝试登录的用户信息【用户唯一标识：{}，登录方式：{}，凭据：{}，授权平台：{}】", userOnlyId, loginType, userCredential, othType);
                //重新组装一下，后面执行认证逻辑时用
                String key = userOnlyId + ':' + othType + ':' + loginType;
                authRequest = UsernamePasswordAuthenticationToken.unauthenticated(key, userCredential);
            } catch (IOException e) {
                log.error("登录请求体解析失败！", e);
                authRequest = new UsernamePasswordAuthenticationToken(
                        "", "");
            }
            // 调用setDetails方法设置登录详情
            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
            log.info("开始验权...");
            //通过getAuthenticationManager()获取认证管理器，并调用authenticate方法进行认证，返回认证结果。
            Authentication authentication = this.getAuthenticationManager().authenticate(authRequest);
            log.info("验权结果{}", authentication.isAuthenticated());
            return authentication;
        } else {
            //不是JSON类型调用父类的attemptAuthentication方法处理
            return super.attemptAuthentication(request, response);
        }
    }
}
